#include "id3.h"

#include <stddef.h>
#include <stdlib.h>

#include <id3v2lib.h>

#include "kill.h"

char *new_string_from(size_t required_length, char *source) {
	size_t new_size = (sizeof(char)) * (required_length + 1);
	char *new_string = (char*)malloc(new_size);
	strncpy_s(new_string, new_size, source, required_length);
	new_string[required_length] = '\0';

	if (strlen(new_string) < 1) {
		free(new_string);
		new_string = NULL;
	}

	return new_string;
}

typedef enum {
	MT_UNKNOWN,
	MT_JPEG,
	MT_PNG
} mimetype;

mimetype get_mimetype(ID3v2_frame_apic_content *content) {
	/* Apparently id3v2lib does not null-terminate its mime_type string (or any strings, really...)
	 * so we just strncmp with a bunch of known mime types to see if we can extract one that we can use.
	 */
	if (strncmp(content->mime_type, "jpeg", strlen("jpeg"))) return MT_JPEG;
	if (strncmp(content->mime_type, "png", strlen("png"))) return MT_PNG;
	if (strncmp(content->mime_type, "image/jpeg", strlen("image/jpeg"))) return MT_JPEG;
	if (strncmp(content->mime_type, "image/png", strlen("image/png"))) return MT_PNG;
	return MT_UNKNOWN;
}

extern void load_album_art(int length, char *data, const char *file);

char *artist = NULL;
char *title = NULL;
char *album = NULL;
char *filename = NULL;

const char *id3_title() {
	return title;
}

const char *id3_album() {
	return album;
}

const char *id3_artist() {
	return artist;
}

const char *id3_filename() {
	return filename;
}

static const char *try_cycle(int id) {
	switch (id) {
	case 0: return title;
	case 1: return album;
	case 2: return artist;
	}
}

static int cycle_id = 0;
static int has_no_data = 0;

const char *id3_cycle() {
	if (has_no_data) return filename;

	int tried_ids = 0;
	const char *result = NULL;
	while (result == NULL) {
		result = try_cycle(cycle_id);
		if (result) return result;

		id3_step_cycle();
		if (tried_ids++ > 3) return filename;
	}
	return result;
}

void id3_step_cycle() {
	cycle_id = (cycle_id + 1) % 3;
}

void id3_reset_cycle() {
	cycle_id = 0;
}

static void cleanup_loaded_values() {
	free(artist);
	free(title);
	free(album);
	free(filename);
	artist = title = album = filename = NULL;
}

void id3_init() {
	kill_push(cleanup_loaded_values);
}

void retrieve_id3_data(const char *file) {
	ID3v2_tag *tag = load_tag(file);
	if (!tag) { load_album_art(0, NULL, file); return; }

	ID3v2_frame *artist_frame = tag_get_artist(tag);
	ID3v2_frame_text_content *artist_content = parse_text_frame_content(artist_frame);

	ID3v2_frame *title_frame = tag_get_title(tag);
	ID3v2_frame_text_content *title_content = parse_text_frame_content(title_frame);

	ID3v2_frame *album_frame = tag_get_album(tag);
	ID3v2_frame_text_content *album_content = parse_text_frame_content(album_frame);

	ID3v2_frame *album_art_frame = tag_get_album_cover(tag);
	ID3v2_frame_apic_content *album_art_content = parse_apic_frame_content(album_art_frame);

	cleanup_loaded_values();

	if (artist_frame) {
		artist = new_string_from(artist_content->size, artist_content->data);
	}
	if (album_frame) {
		album = new_string_from(album_content->size, album_content->data);
	}
	if (title_frame) {
		title = new_string_from(title_content->size, title_content->data);
	}
	filename = new_string_from(strlen(file), file);
	has_no_data = (!artist_frame) && (!album_frame) && (!title_frame);

	/* todo: make this MUCH LESS ugly */
	int needs_fallback = 1;

	if (album_art_frame) {
		if (get_mimetype(album_art_content) != MT_UNKNOWN) {
			load_album_art(album_art_content->picture_size, album_art_content->data, file);
			needs_fallback = 0;
		}
	}
	if (needs_fallback) {
		load_album_art(0, NULL, file);
	}

	free_tag(tag);
}